package ontosim

import org.springframework.dao.DataIntegrityViolationException
import java.net.*

import org.semanticweb.owlapi.apibinding.OWLManager
import org.semanticweb.owlapi.model.*
import org.semanticweb.owlapi.reasoner.*
import org.semanticweb.owlapi.profiles.*
import org.semanticweb.owlapi.util.*
import org.semanticweb.owlapi.io.*
import org.semanticweb.elk.owlapi.*

import org.apache.http.client.methods.*
import org.apache.http.client.*
import org.apache.http.*
import org.apache.http.impl.client.*

class WorkspaceController {

  final static String apikey = "24e0413e-54e0-11e0-9d7b-005056aa3316"

  static allowedMethods = [save: "POST", update: "POST", delete: "POST"]

  /* queries BioPortal for a single class URI and returns a set composed of the class and all its superclasses */
  def queryBioPortal(String uri) {
    def prefix = ""
    prefix += "PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>\n"
    prefix += "PREFIX skos: <http://www.w3.org/2004/02/skos/core#>\n"
    prefix += "PREFIX omv: <http://http://omv.ontoware.org/2005/05/ontology#>\n"

    def query = ""
    query += "SELECT DISTINCT ?cat\n"
    query += "WHERE \n"
    query += "{ \n"
    query += "<$uri> rdfs:subClassOf ?cat .\n"
    query += "}"
  }

  // /* runs query on endpoint without apikey */
  // def querySparql(String endpoint, String query) {
  //   return querySparql(endpoint, query, null)
  // }

  /* runs query on endpoint */
    def querySparql(String endpoint, String query, String apikey) {
    HttpClient httpclient = new DefaultHttpClient();
    // Prepare a request object
    try {
      def ep = endpoint
      def qs = "query="
      qs += URLEncoder.encode(query, "UTF-8")
      qs += "&timeout="
      qs += URLEncoder.encode("0", "UTF-8")
      qs += "&format="
      qs += URLEncoder.encode("text", "UTF-8")

      def queryURL = null
      if (apikey == null) {
	queryURL = ep+"?"+qs
      } else {
	queryURL = ep+"?"+qs+"&apikey="+apikey
      }
      println queryURL
      HttpGet httpget = new HttpGet(queryURL)
      
      HttpResponse response = httpclient.execute(httpget)
      HttpEntity entity = response.getEntity()

      // If the response does not enclose an entity, there is no need
      // to worry about connection release
      if (entity != null) {
	InputStream instream = entity.getContent();
	try {
	  
	  BufferedReader reader = new BufferedReader(
	    new InputStreamReader(instream))
	  // do something useful with the response
	  return reader.getText()
	} catch (Exception ex) {
	  return null
	} finally {
	  // Closing the input stream will trigger connection release
	  instream.close();
	}
	// When HttpClient instance is no longer needed,
	// shut down the connection manager to ensure
	// immediate deallocation of all system resources
	httpclient.getConnectionManager().shutdown();
      }
    } catch (Exception E) {}
    
  }

  Float jaccard(def s1, def s2) {
    def inter = 0.0
    def un = 0.0
    s1.each {
      if (s2.contains(it)) {
	inter+=1
      }
      un+=1
    }
    s2.each { un+=1 }
    un-=inter
    if (un == 0.0) {
      return 0.0
    } else {
      return inter/un
    }
  }

  def fileUpload = {
    def omap = servletContext.getAttribute("omap")
    
    def webRootDir = servletContext.getRealPath("/")
    def userDir = new File(webRootDir, "/dataupload/")
    userDir.mkdirs()
    def map1 = [:]
    def map2 = [:]
    try {
      def uploadedFile = request.getFile('file1')
      uploadedFile.transferTo( new File( userDir, uploadedFile.originalFilename))
      File f = new File( userDir, uploadedFile.originalFilename)
      f.splitEachLine("\t") { line ->
	def entity = line[0]
	def ontologyTerm = line[1]
	if (map1[entity] == null) {
	  map1[entity] = new TreeSet()
	}
	map1[entity] << ontologyTerm
      }
    } catch (Exception E) {}
    try {
      def uploadedFile = request.getFile('file2')
      uploadedFile.transferTo( new File( userDir, uploadedFile.originalFilename))
      File f = new File( userDir, uploadedFile.originalFilename)
      f.splitEachLine("\t") { line ->
	def entity = line[0]
	def ontologyTerm = line[1]
	if (map2[entity] == null) {
	  map2[entity] = new TreeSet()
	}
	map2[entity] << ontologyTerm
      }
    } catch (Exception E) {}
    map1.each { k, v ->
      def s = new TreeSet()
      v?.each { 
	if (omap[it]!=null) {
	  s.addAll(omap[it]) 
	}
      }
      map1[k] = s
    }
    map2.each { k, v ->
      def s = new TreeSet()
      v?.each { 
	if (omap[it]!=null) {
	  s.addAll(omap[it]) 
	}
      }
      map2[k] = s
    }
    map1.each { k1, v1 ->
      map2.each { k2, v2 ->
	println "$k1\t$k2\t"+jaccard(v1, v2)
      }
    }
    redirect(action:"list")
  }

  def runSparqlQuery = {
    session.q1 = new ontosim.SparqlQuery()
    session.q2 = new ontosim.SparqlQuery()
    session.q1.endpoint = params.endpoint1
    session.q2.endpoint = params.endpoint2
    session.q1.query = params.query1
    session.q2.query = params.query2

    def results = new XmlSlurper().parseText(querySparql(session.q1.endpoint, session.q1.query))
    results.results.result.each { res ->
      println res.binding.each { 
	println it.uri
      }
    }
    
    redirect(action:"list")
  }

  def index() {
    redirect(action: "list", params: params)
  }

  def list(Integer max) {
    params.max = Math.min(max ?: 10, 100)
    [workspaceInstanceList: Workspace.list(params), workspaceInstanceTotal: Workspace.count()]
  }

  

  def create() {
    [workspaceInstance: new Workspace(params)]
  }

  def save() {
    def workspaceInstance = new Workspace(params)
    if (!workspaceInstance.save(flush: true)) {
      render(view: "create", model: [workspaceInstance: workspaceInstance])
      return
    }

    flash.message = message(code: 'default.created.message', args: [message(code: 'workspace.label', default: 'Workspace'), workspaceInstance.id])
    redirect(action: "show", id: workspaceInstance.id)
  }

  def show(Long id) {
    def workspaceInstance = Workspace.get(id)
    if (!workspaceInstance) {
      flash.message = message(code: 'default.not.found.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "list")
      return
    }

    [workspaceInstance: workspaceInstance]
  }

  def edit(Long id) {
    def workspaceInstance = Workspace.get(id)
    if (!workspaceInstance) {
      flash.message = message(code: 'default.not.found.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "list")
      return
    }

    [workspaceInstance: workspaceInstance]
  }

  def update(Long id, Long version) {
    def workspaceInstance = Workspace.get(id)
    if (!workspaceInstance) {
      flash.message = message(code: 'default.not.found.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "list")
      return
    }

    if (version != null) {
      if (workspaceInstance.version > version) {
	workspaceInstance.errors.rejectValue("version", "default.optimistic.locking.failure",
					     [message(code: 'workspace.label', default: 'Workspace')] as Object[],
					     "Another user has updated this Workspace while you were editing")
	render(view: "edit", model: [workspaceInstance: workspaceInstance])
	return
      }
    }

    workspaceInstance.properties = params

    if (!workspaceInstance.save(flush: true)) {
      render(view: "edit", model: [workspaceInstance: workspaceInstance])
      return
    }

    flash.message = message(code: 'default.updated.message', args: [message(code: 'workspace.label', default: 'Workspace'), workspaceInstance.id])
    redirect(action: "show", id: workspaceInstance.id)
  }

  def delete(Long id) {
    def workspaceInstance = Workspace.get(id)
    if (!workspaceInstance) {
      flash.message = message(code: 'default.not.found.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "list")
      return
    }

    try {
      workspaceInstance.delete(flush: true)
      flash.message = message(code: 'default.deleted.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "list")
    }
    catch (DataIntegrityViolationException e) {
      flash.message = message(code: 'default.not.deleted.message', args: [message(code: 'workspace.label', default: 'Workspace'), id])
      redirect(action: "show", id: id)
    }
  }
}
